package com.example.testuploadfile.download;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

public class MultiThreadFileDownloader {

    private static final int CHUNK_SIZE = 10 * 1024 * 1024; // 每个分片大小：10MB

    private static final int BUFFER_SIZE = 8192; // 每次读取的缓冲区大小（8 KB）

    public static void downloadFile(String fileURL, String destinationFilePath) throws IOException, InterruptedException, ExecutionException {
        // 获取文件总大小
        HttpURLConnection connection = (HttpURLConnection) new URL(fileURL).openConnection();
        connection.setRequestMethod("HEAD"); // 只请求文件头信息
        int fileSize = connection.getContentLength();
        String contentType = connection.getContentType();
        System.out.println("contentType: " + contentType);
        System.out.println("文件大小: " + fileSize/1024/1024+"MB");
        connection.disconnect();

        // 计算需要的分片数
        int chunksCount = (fileSize + CHUNK_SIZE - 1) / CHUNK_SIZE; // 向上取整计算需要多少个分片


        // 用于记录总体下载进度
        AtomicLong totalBytesDownloaded = new AtomicLong(0);

        // 使用线程池进行并发下载
        ExecutorService executorService = Executors.newFixedThreadPool(chunksCount);
        List<Future<Void>> futures = new ArrayList<>();

        // 启动线程下载文件的各个部分
        for (int i = 0; i < chunksCount; i++) {
            long startByte = i * CHUNK_SIZE;
            long endByte = Math.min(startByte + CHUNK_SIZE - 1, fileSize - 1);
            futures.add(executorService.submit(new DownloadTask(fileURL, destinationFilePath, startByte, endByte, i, totalBytesDownloaded, fileSize)));
        }

        // 定期打印下载进度
        ExecutorService progressExecutor = Executors.newSingleThreadExecutor();
        progressExecutor.submit(() -> {
            int lastReportedProgress = 0;
            while (true) {
                long downloadedBytes = totalBytesDownloaded.get();
                int progress = (int) ((downloadedBytes * 100) / fileSize);
                // 每当下载进度增加了 10% 时才记录进度
                if (progress >= lastReportedProgress + 10) {
                    lastReportedProgress = progress;
                    System.out.println("总体下载进度: " + progress + "% (" + downloadedBytes + "/" + fileSize + " bytes)");
                }
                // 当下载完成时退出
                if (downloadedBytes == fileSize) {
                    break;
                }
            }
        });

        // 等待所有任务完成
        for (Future<Void> future : futures) {
            future.get();
        }

        executorService.shutdown();
        progressExecutor.shutdown();
        System.out.println("文件下载成功！");
    }

    public static void main(String[] args) {
        String fileURL = "https://vdept3.bdstatic.com/mda-qmfinpvwmvymhs8e/360p/h264/1734356030067613385/mda-qmfinpvwmvymhs8e.mp4?v_from_s=hkapp-haokan-nanjing&auth_key=1737549335-0-0-5c1e16a7028a5961245f41fbe3c5a6f9&bcevod_channel=searchbox_feed&pd=1&cr=0&cd=0&pt=3&logid=2135315057&vid=16232853081927957277&klogid=2135315057&abtest="; // 目标文件的 URL
        String destinationFilePath = "C:\\Users\\84186\\Desktop\\downloaded_file.mp4"; // 下载后保存的文件路径

        try {
            long startTime = System.currentTimeMillis();
            downloadFile(fileURL, destinationFilePath);
            long endTime = System.currentTimeMillis();
            System.out.println("下载成功,总耗时: " + (endTime - startTime) / 1000 / 60 + "分钟");
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
            System.out.println("文件下载失败！");
        }
    }

    private static class DownloadTask implements Callable<Void> {
        private final String fileURL;
        private final String destinationFilePath;
        private final long startByte;
        private final long endByte;
        private final int partNumber;
        private final AtomicLong totalBytesDownloaded;
        private final int fileSize;

        public DownloadTask(String fileURL, String destinationFilePath, long startByte, long endByte, int partNumber, AtomicLong totalBytesDownloaded, int fileSize) {
            this.fileURL = fileURL;
            this.destinationFilePath = destinationFilePath;
            this.startByte = startByte;
            this.endByte = endByte;
            this.partNumber = partNumber;
            this.totalBytesDownloaded = totalBytesDownloaded;
            this.fileSize = fileSize;
        }

        @Override
        public Void call() throws Exception {
            HttpURLConnection connection = (HttpURLConnection) new URL(fileURL).openConnection();
            connection.setRequestProperty("Range", "bytes=" + startByte + "-" + endByte);
            connection.connect();

            try (InputStream in = connection.getInputStream(); RandomAccessFile file = new RandomAccessFile(destinationFilePath, "rw")) {

                file.seek(startByte);
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    file.write(buffer, 0, bytesRead);
                    totalBytesDownloaded.addAndGet(bytesRead);  // 更新已下载的字节数
                }
            } finally {
                connection.disconnect();
            }

            System.out.println("Part " + partNumber + " 下载完成!");
            return null;
        }
    }
}
